package org.lc.kcjxzj.textcheck;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

/**
 * 改进的连续字符相似度计算器
 * 
 * 改进点：
 * 1. 动态最小匹配长度
 * 2. 使用滚动数组优化空间
 * 3. 改进匹配算法
 * 4. 特殊处理中文文本
 */
@Slf4j
@Component
public class ConsecutiveSimilarity implements SimilarityCalculator {
    
    // 默认最小匹配长度
    private static final int DEFAULT_MIN_LENGTH = 10;
    
    // 存储匹配的子串信息
    private static class Match {
        int start1, start2, length;
        Match(int start1, int start2, int length) {
            this.start1 = start1;
            this.start2 = start2;
            this.length = length;
        }
    }
    
    @Override
    public double calculate(String text1, String text2) {
        // 处理特殊情况
        if (text1 == null || text2 == null) {
            return 0.0;
        }
        if (text1.isEmpty() && text2.isEmpty()) {
            return 1.0;
        }
        if (text1.isEmpty() || text2.isEmpty()) {
            return 0.0;
        }

        // 预处理文本
        text1 = normalizeText(text1);
        text2 = normalizeText(text2);

        int len1 = text1.length();
        int len2 = text2.length();
        
        // 计算动态最小匹配长度
        int minMatchLength = calculateMinMatchLength(len1, len2);
        
        // 使用滚动数组实现动态规划
        // last[j]存储上一行的值，curr[j]存储当前行的值
        int[] last = new int[len2];
        int[] curr = new int[len2];
        
        // 存储所有匹配的子串
        List<Match> matches = new ArrayList<>();
        
        // 动态规划找出所有匹配
        for (int i = 0; i < len1; i++) {
            for (int j = 0; j < len2; j++) {
                if (text1.charAt(i) == text2.charAt(j)) {
                    curr[j] = (j > 0 ? last[j - 1] : 0) + 1;
                    
                    if (curr[j] >= minMatchLength) {
                        // 修复越界判断：先检查边界再比较字符
                        boolean isEndOfText = (i == len1 - 1) || (j == len2 - 1);
                        boolean nextCharMismatch = !isEndOfText && 
                            (text1.charAt(i + 1) != text2.charAt(j + 1));
                            
                        if (isEndOfText || nextCharMismatch) {
                            matches.add(new Match(
                                i - curr[j] + 1,
                                j - curr[j] + 1,
                                curr[j]
                            ));
                        }
                    }
                } else {
                    curr[j] = 0;
                }
            }
            
            // 交换数组
            int[] temp = last;
            last = curr;
            curr = temp;
        }
        
        // 移除重叠的匹配
        matches = removeOverlappingMatches(matches);
        
        // 计算总匹配长度
        int totalMatchLength = 0;
        for (Match match : matches) {
            totalMatchLength += match.length;
        }
        
        // 计算相似度
        double similarity = (double) totalMatchLength / Math.min(len1, len2);
        
        // 调整相似度
        return adjustSimilarity(similarity, text1, text2);
    }
    
    /**
     * 规范化文本
     */
    private String normalizeText(String text) {
        if (text == null) return "";
        return text.trim()
                  .replaceAll("\\s+", " ")     // 统一空白字符
                  .replaceAll("[\\p{P}]", ""); // 移除标点符号
    }
    
    /**
     * 计算动态最小匹配长度
     * 根据文本长度动态调整最小匹配长度
     */
    private int calculateMinMatchLength(int len1, int len2) {
        int minLength = Math.min(len1, len2);
        
        if (minLength < 20) {
            // 短文本使用较小的阈值
            return Math.min(DEFAULT_MIN_LENGTH, minLength / 2);
        } else if (minLength < 100) {
            // 中等长度文本
            return Math.min(DEFAULT_MIN_LENGTH, minLength / 4);
        } else {
            // 长文本使用固定阈值
            return DEFAULT_MIN_LENGTH;
        }
    }
    
    /**
     * 移除重叠的匹配
     * 保留较长的匹配，移除被包含的较短匹配
     */
    private List<Match> removeOverlappingMatches(List<Match> matches) {
        List<Match> result = new ArrayList<>();
        
        // 按长度降序排序
        matches.sort((a, b) -> Integer.compare(b.length, a.length));
        
        for (Match current : matches) {
            boolean overlaps = false;
            
            // 检查是否与已保留的匹配重叠
            for (Match existing : result) {
                if (isOverlapping(current, existing)) {
                    overlaps = true;
                    break;
                }
            }
            
            if (!overlaps) {
                result.add(current);
            }
        }
        
        return result;
    }
    
    /**
     * 检查两个匹配是否重叠
     */
    private boolean isOverlapping(Match m1, Match m2) {
        // 修改为需要同时在两个维度上都重叠才算真正重叠
        boolean overlaps1 = (m1.start1 < m2.start1 + m2.length) && 
                          (m1.start1 + m1.length > m2.start1);
        boolean overlaps2 = (m1.start2 < m2.start2 + m2.length) && 
                          (m1.start2 + m1.length > m2.start2);
        return overlaps1 && overlaps2;
    }
    
    /**
     * 调整相似度
     */
    private double adjustSimilarity(double similarity, String text1, String text2) {
        // 计算长度比例
        int maxLength = Math.max(text1.length(), text2.length());
        int minLength = Math.min(text1.length(), text2.length());
        double lengthRatio = (double) minLength / maxLength;
        
        // 根据文本长度调整相似度
        if (maxLength < 20) {
            // 短文本需要更严格的相似度要求
            similarity = similarity * (0.7 + 0.3 * lengthRatio);
        } else if (maxLength > 100) {
            // 长文本的相似度适当提升
            similarity = similarity * (0.9 + 0.1 * lengthRatio);
        } else {
            // 中等长度文本
            similarity = similarity * (0.8 + 0.2 * lengthRatio);
        }
        
        return Math.max(0.0, Math.min(1.0, similarity));
    }
}